/***************************************************************************************
 The copyright in this software is being made available under the BSD License, included
 below. This software may be subject to other third party rights,including patent rights,
 and no such rights are granted under this license.

 Regents of the Tsinghua University, Peking University, Zhejiang University, HKUST
 Tsinghua University, Peking University, Zhejiang University, HKUST 2011

 Copyright (c) 2011, Regents of the Tsinghua University, Peking University, Zhejiang
 University, HKUST. All Rights Reserved.

 Redistribution and use in source and binary forms, with or without modification, are
 permitted provided that the following conditions are met:
   * Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   * Neither the names of the copyright holders nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 OF SUCH DAMAGE.
***************************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/timeb.h>
#include <assert.h>

#if defined WIN32 && !defined(__MINGW32__)
#include <conio.h>
#include <IO.H>
#endif

#include <fcntl.h>

#include "contributors.h"
#include "global.h"
#include "memalloc.h"
#include "bbv.h"

#define LOGFILE     "log.dec"
#define DATADECFILE "dataDec.txt"
#define TRACEFILE   "trace_dec.txt"

extern FILE *bits;

input_t *input;
snr_t *snr;
image_t *img;

bitstream_t *currStream;
FILE *reffile, *reffile2;

extern bbv_buffer_t *pBbv;

/*
*************************************************************************
* Function:main function for TML decoder
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

int main( int argc, char **argv )
{
    // allocate memory for the structures
    if ( ( input = ( input_t * )calloc( 1, sizeof( input_t ) ) ) == NULL )
        no_mem_exit( "main: input" );
    if ( ( snr = ( snr_t * )calloc( 1, sizeof( snr_t ) ) ) == NULL )
        no_mem_exit( "main: snr" );
    if ( ( img = ( image_t * )calloc( 1, sizeof( image_t ) ) ) == NULL )
        no_mem_exit( "main: img" );

    img->seq_header_indicate = 0;
    img->B_discard_flag = 0;

    currStream = alloc_bitstream();
    qcoder = alloc_qcoder();

    eos = 0;
    CSyntax = 1;

    init_conf( input, argc, argv );

    open_input_bitstream( input->infile );

    // Allocate Slice data struct
    init( img );
    img->number = 0;

    img->next_frame_type = I_IMG; //xy_110703
    img->imgtr_last_P = 0;
    img->imgtr_next_P = 0;

    img->new_seq_header_flag = 1;
    img->new_sequence_flag = 1;

    vec_flag = 0;

    FrameNum = 0;

    Bframe_ctr = 0;

    tot_time = 0;
    do
    {
        while ( ( decode_one_frame( img, input, snr ) != EOS ) && ( !is_end_of_bitstream() ) ) ;
    }
    while ( !is_end_of_bitstream() );

    if ( CSyntax )
    {
#if SYNTAX_REPORT
        fprintf( p_sreport, "\nALL SYNTAX IS CORRECT!\n" );
#endif
    }

    eos = 1;

#if REC_YUV
    if ( p_ref )
        find_snr( snr, img, p_ref ); // if ref sequence exist
#endif


#if REC_YUV
    if ( pre_img_type == I_IMG )  // I picture
        fprintf( stdout, "%3d(I)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s\n", FrameNum, pre_img_tr, pre_img_qp, snr->snr_y, snr->snr_u, snr->snr_v, pre_tmp_time, 1 /*img->picture_structure*/ ? "FRM" : "FLD" );
    else if ( pre_img_type == P_IMG )     // P pictures
    {
        if ( pre_img_types == I_IMG )
            fprintf( stdout, "%3d(I)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s\n", FrameNum, pre_img_tr, pre_img_qp, snr->snr_y, snr->snr_u, snr->snr_v, pre_tmp_time, 1 /*img->picture_structure*/ ? "FRM" : "FLD" );   //jlzheng 7.3
        else
            fprintf( stdout, "%3d(P)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s\n", FrameNum, pre_img_tr, pre_img_qp, snr->snr_y, snr->snr_u, snr->snr_v, pre_tmp_time, 1 /*img->picture_structure*/ ? "FRM" : "FLD" );
    }
#else
    if ( pre_img_type == I_IMG )  // I picture
        fprintf( stdout, "%3d(I)  %3d %5d %5d\t\t%s\n", FrameNum, pre_img_tr, pre_img_qp, pre_tmp_time, 1 /*img->picture_structure*/ ? "FRM" : "FLD" );
    else if ( pre_img_type == P_IMG )     // P pictures
    {
        if ( pre_img_types == I_IMG )
            fprintf( stdout, "%3d(I)  %3d %5d %5d\t\t%s\n", FrameNum, pre_img_tr, pre_img_qp, pre_tmp_time, 1 /*img->picture_structure*/ ? "FRM" : "FLD" );   //jlzheng 7.3
        else
            fprintf( stdout, "%3d(P)  %3d %5d %5d\t\t%s\n", FrameNum, pre_img_tr, pre_img_qp, pre_tmp_time, 1 /*img->picture_structure*/ ? "FRM" : "FLD" );
    }
#endif

    report_frame( snr, pre_tmp_time );

    // B PICTURE : save the last P picture
    write_prev_Pframe( img, p_out );

    if ( input->check_BBV_flag )
    {
        stat_bbv_buffer( pBbv );
        pBbv = free_bbv_memory( pBbv );
    }

    report( input, img, snr );
    free_bitstream();
    free( qcoder );
    free_global_buffers( input, img );

    close_input_bitstream();

#if defined(WIN32) && !defined(__MINGW32__)
    _close( p_out );
#if REC_YUV
    if ( p_ref )
        _close( p_ref );
#endif
#else
    fclose( p_out );
#if REC_YUV
    if ( p_ref )
        fclose( p_ref );
#endif
#endif

#if TRACE
    fclose( p_trace );
#endif

#if SYNTAX_REPORT
    if ( p_sreport )
        fclose( p_sreport );
#endif

    free( input );
    free( snr );
    free( img );

    return 0;
}

/*
*************************************************************************
* Function:Initilize some arrays
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

void init( image_t *img )
{
    int i;

    for ( i = 0; i < 256; i++ )
    {
        img->quad[i] = i * i;
    }

}

/*
*************************************************************************
* Function:Read input from configuration file
* Input:Name of configuration filename
* Output:
* Return:
* Attention:
*************************************************************************
*/

void init_conf( input_t *inp, int numpar, char **config_str )
{
    FILE *fd;

    inp->check_BBV_flag = 0;
    if ( numpar > 4 )
    {
        snprintf( errortext, ET_SIZE, "Usage: %s <config.dat> <bitstreamfilename> <decfilename> <reffilename> \n \
                                 ?-the decoder can be configured by configfile or by command line \n \
                                 ?-param with only <config.dat> defines decoder with file\n \
                                 ?-params with allof the params define decoder params with command line\n \
                                 ", config_str[0] );
        error( errortext, 300 );
    }

    if ( numpar == 1 )
    {
        fprintf( stdout, "**************************************************************************\n" );
        fprintf( stdout, "The decoder config file doesn't exist. Use the default parameters instead!\n" );
        fprintf( stdout, "**************************************************************************\n\n" );
        snprintf( errortext, ET_SIZE, "Usage: %s <config.dat>\n \
                                 or %s <bitstreamfilename> <decfilename> [reffilename] \n \
                                 -the decoder can be configured by configfile or by command line \n \
                                 -param with only <config.dat> defines decoder with file\n \
                                 -params with allof the params define decoder params with command line\n \
                                 ", config_str[0], config_str[0] );
        fprintf( stderr, "%s\n", errortext );
    }

    if ( numpar == 2 )
        if ( ( fd = fopen( config_str[1], "r" ) ) == NULL )
        {
            snprintf( errortext, ET_SIZE, "Error: Control file %s not found\n", config_str[1] );
            error( errortext, 300 );
        }
    strcpy( inp->infile, "test.bit" );
    strcpy( inp->outfile, "test_dec.yuv" );
    strcpy( inp->reffile, "test_rec.yuv" );
    inp->buf_cycle = 2;
    inp->LFParametersFlag = 0;
    inp->yuv_structure = 0;
    inp->check_BBV_flag = 0;

    if ( numpar == 2 )
    {
        int cnt; 
        cnt = fscanf( fd, "%s", inp->infile );    // compressed input bitsream
        if (cnt == 0){
            snprintf( errortext, ET_SIZE, "Error: read infile %s error\n", inp->infile );
            error( errortext, 300 );
        }
        cnt = fscanf( fd, "%*[^\n]" );

        cnt =fscanf( fd, "%s", inp->outfile );   // YUV output format
        if (cnt == 0){
            snprintf( errortext, ET_SIZE, "Error: read outfile %s error\n", inp->outfile );
            error( errortext, 300 );
        }
        cnt = fscanf( fd, "%*[^\n]" );

#if REC_YUV
        cnt = fscanf( fd, "%s", inp->reffile );   // reference file
        if (cnt == 0){
            snprintf( errortext, ET_SIZE, "Error: read reffile %s error\n", inp->reffile );
            error( errortext, 300 );
        }
        cnt = fscanf( fd, "%*[^\n]" );
#endif

        // Frame buffer size
        //fscanf(fd, "%d,", &inp->buf_cycle); //
        //fscanf(fd, "%*[^\n]");


        //fscanf(fd, "%d,", &inp->LFParametersFlag);
        //fscanf(fd, "%*[^\n]");

        //fscanf(fd, "%d,", &inp->yuv_structure);
        //fscanf(fd, "%*[^\n]");

        //fscanf(fd, "%d,", &inp->check_BBV_flag);
        //fscanf(fd, "%*[^\n]");

    }

    if ( numpar > 2 )            //The decoder will be configured with the command line in the case of 9 parameters input
    {

        strcpy( inp->infile, config_str[1] );
        strcpy( inp->outfile, config_str[2] );

#if REC_YUV
        strcpy( inp->reffile, config_str[3] );   // reference file
#endif

        //inp->buf_cycle = atoi(config_str[5]);
        //inp->LFParametersFlag = atoi(config_str[6]);
        //inp->yuv_structure = atoi(config_str[7]);

        //inp->check_BBV_flag = atoi(config_str[8]);
    }

    //if (inp->buf_cycle < 1)
    //{
    //  snprintf(errortext, ET_SIZE, "Frame Buffer Size is %d. It has to be at least 1", inp->buf_cycle);
    //  error(errortext, 1);
    //}

#if TRACE
    if ( ( p_trace = fopen( TRACEFILE, "w" ) ) == 0 ) // append new statistic at the end
    {
        snprintf( errortext, ET_SIZE, "Error open file %s!", TRACEFILE );
        error( errortext, 500 );
    }
#endif

#if SYNTAX_REPORT
    if ( ( p_sreport = fopen( "syntaxreport.dat", "a+" ) ) == 0 )
    {
        snprintf( errortext, ET_SIZE, "Error open file %s!", "syntaxreport.dat" );
        error( errortext, 500 );
    }

    fprintf( p_sreport, "\n-----------------------------------------------------------------\n" );
    fprintf( p_sreport, "*****************************************************************\n" );
    fprintf( p_sreport, "**THE SYNTAX CHECKING MECHANISM IS OUT-DATED                   **\n" );
    fprintf( p_sreport, "*****************************************************************\n" );
    fprintf( p_sreport, "File Name: %s", input->infile );
    fprintf( p_sreport, "\nUsage:\n" );
    fprintf( p_sreport, "Error Code:\n" );
    fprintf( p_sreport, "0: Invalid deltaQP. ImageQP out of the range [0,63], section 7.2.5&9.4.7 @ N1572\n" );
    fprintf( p_sreport, "1: Quantization coefficient's value out of the range [-2048,2047], section 9.6.4 @ N1572\n" );
    fprintf( p_sreport, "2: De-Quantization coefficient's value out of the range [-8192,8191], section 9.6.4 @ N1572\n" );
    fprintf( p_sreport, "3: mv_diff_x or mv_diff_y out of the range [-4096, 4095], section 7.2.5 @ N1572\n" );
    fprintf( p_sreport, "4: Motion Vector out of the range specified at section B.2 @ N1572\n" );
    fprintf( p_sreport, "Example:\n" );
    fprintf( p_sreport, "error(0)       (deltaQP,ImgQP) @ MBidx\n" );
    fprintf( p_sreport, "error(1)           quant-value @ (y,x) Blkidx MBidx\n" );
    fprintf( p_sreport, "error(2)         dequant-value @ (y,x) Blkidx MBidx\n" );
    fprintf( p_sreport, "error(3)               mv_diff @ Blkidx MBidx\n" );
    fprintf( p_sreport, "error(4)                mv|pos @ Blkidx MBidx\n" );
    fprintf( p_sreport, "\nStart To Check The Syntax\n" );
    CSyntax = 1;
#endif

#if defined(WIN32) && !defined(__MINGW32__)
    if ( ( p_out = _open( inp->outfile, _O_WRONLY | _O_CREAT | _O_BINARY | _O_TRUNC, _S_IREAD | _S_IWRITE ) ) == -1 )
#else
    if ( ( p_out = fopen( inp->outfile, "wb" ) ) == 0 )
#endif
    {
        snprintf( errortext, ET_SIZE, "Error open file %s ", inp->outfile );
        error( errortext, 500 );
    }

    fprintf( stdout, "--------------------------------------------------------------------------\n" );
    fprintf( stdout, " Decoder config file              : %s \n", config_str[0] );
    fprintf( stdout, "--------------------------------------------------------------------------\n" );
    fprintf( stdout, " Input  bitstream                 : %s \n", inp->infile );
    fprintf( stdout, " Output decoded YUV               : %s \n", inp->outfile );
    fprintf( stdout, " Output status file               : %s \n", LOGFILE );

#if REC_YUV
#if defined(WIN32) && !defined(__MINGW32__)
    if ( ( p_ref = _open( input->reffile, O_RDONLY | O_BINARY | _O_CREAT ) ) == -1 )
#else
    if ( ( p_ref = fopen( inp->reffile, "rb" ) ) == 0 )
#endif
    {
        //fprintf(stdout, " Input reference file                   : %s does not exist \n", inp->reffile);
        //fprintf(stdout, "                                          SNR values are not available\n");
        RefPicExist = 0;
    }
    else
    {
        //fprintf(stdout, " Input reference file                   : %s \n", inp->reffile);
        RefPicExist = 1;
    }

    fprintf( stdout, "--------------------------------------------------------------------------\n" );
    fprintf( stdout, " Frame   TR    QP   SnrY    SnrU    SnrV   Time(ms)   FRM/FLD\n" );
#else
    RefPicExist = 0;
    fprintf( stdout, "--------------------------------------------------------------------------\n" );
    fprintf( stdout, " Frame   TR    QP   Time(ms)   FRM/FLD\n" );
#endif
}

/*
*************************************************************************
* Function:Reports the gathered information to appropriate outputs
* Input:
struct inp_par *inp,
struct img_par *img,
struct snr_par *stat
* Output:
* Return:
* Attention:
*************************************************************************
*/

void report( input_t *inp, image_t *img, snr_t *snr )
{
#define OUTSTRING_SIZE 255
    char string[OUTSTRING_SIZE];
    FILE *p_log;

#if defined(WIN32) && !defined(__MINGW32__)
    char timebuf[128];
#else
    time_t now;
    struct tm *l_time;
#endif

    //fprintf(stdout, "-------------------- Average SNR all frames ------------------------------\n");
    //fprintf(stdout, " SNR Y(dB)           : %5.2f\n", snr->snr_ya);
    //fprintf(stdout, " SNR U(dB)           : %5.2f\n", snr->snr_ua);
    //fprintf(stdout, " SNR V(dB)           : %5.2f\n", snr->snr_va);
    fprintf( stdout, " Total decoding time : %.3f sec \n", tot_time * 0.001 );
    fprintf( stdout, "--------------------------------------------------------------------------\n" );

    fprintf( stdout, "\n\n" );
    // write to log file

    snprintf( string, OUTSTRING_SIZE, "%s", LOGFILE );
    if ( ( p_log = fopen( string, "r" ) ) == 0 )  // check if file exist
    {
        if ( ( p_log = fopen( string, "a" ) ) == 0 )
        {
            snprintf( errortext, ET_SIZE, "Error open file %s for appending", string );
            error( errortext, 500 );
        }
        else                        // Create header to new file
        {
            fprintf( p_log, " ------------------------------------------------------------------------------------------\n" );
            fprintf( p_log, "|  Decoder statistics. This file is made first time, later runs are appended               |\n" );
            fprintf( p_log, " ------------------------------------------------------------------------------------------ \n" );
            fprintf( p_log, "| Date  | Time  |    Sequence        |#Img|Format|SNRY 1|SNRU 1|SNRV 1|SNRY N|SNRU N|SNRV N|\n" );
            fprintf( p_log, " ------------------------------------------------------------------------------------------\n" );
        }
    }
    else
    {
        fclose( p_log );
        p_log = fopen( string, "a" ); // File exist,just open for appending
    }

#if defined(WIN32) && !defined(__MINGW32__)
    _strdate( timebuf );
    fprintf( p_log, "| %1.5s |", timebuf );

    _strtime( timebuf );
    fprintf( p_log, " % 1.5s |", timebuf );
#else
    now = time( ( time_t * ) NULL ); // Get the system time and put it into 'now' as 'calender time'
    time( &now );
    l_time = localtime( &now );
    strftime( string, sizeof string, "%d-%b-%Y", l_time );
    fprintf( p_log, "| %1.5s |", string );

    strftime( string, sizeof string, "%H:%M:%S", l_time );
    fprintf( p_log, "| %1.5s |", string );
#endif

    fprintf( p_log, "%20.20s|", inp->infile );

    fprintf( p_log, "%3d |", img->number );

    fprintf( p_log, "%6.3f|", snr->snr_y1 );
    fprintf( p_log, "%6.3f|", snr->snr_u1 );
    fprintf( p_log, "%6.3f|", snr->snr_v1 );
    fprintf( p_log, "%6.3f|", snr->snr_ya );
    fprintf( p_log, "%6.3f|", snr->snr_ua );
    fprintf( p_log, "%6.3f|\n", snr->snr_va );

    fclose( p_log );

    snprintf( string, OUTSTRING_SIZE, "%s", DATADECFILE );
    p_log = fopen( string, "a" );

    if ( Bframe_ctr != 0 )        // B picture used
    {
        fprintf( p_log, "%3d %2d %2d %2.2f %2.2f %2.2f %5d "
                 "%2.2f %2.2f %2.2f %5d " "%2.2f %2.2f %2.2f %5d %.3f\n", img->number, 0, img->qp, snr->snr_y1, snr->snr_u1, snr->snr_v1, 0, 0.0, 0.0, 0.0, 0, snr->snr_ya, snr->snr_ua, snr->snr_va, 0, ( double )0.001 * tot_time / ( img->number + Bframe_ctr - 1 ) );
    }
    else
    {
        fprintf( p_log, "%3d %2d %2d %2.2f %2.2f %2.2f %5d " "%2.2f %2.2f %2.2f %5d " "%2.2f %2.2f %2.2f %5d %.3f\n", img->number, 0, img->qp, snr->snr_y1, snr->snr_u1, snr->snr_v1, 0, 0.0, 0.0, 0.0, 0, snr->snr_ya, snr->snr_ua, snr->snr_va, 0, ( double )0.001 * tot_time / img->number );
    }
    fclose( p_log );
}

/*
*************************************************************************
* Function:Allocates a Bitstream
* Input:
* Output:allocated Bitstream point
* Return:
* Attention:
*************************************************************************
*/

bitstream_t *alloc_bitstream()
{
    bitstream_t *bitstream;

    bitstream = ( bitstream_t * ) calloc( 1, sizeof( bitstream_t ) );
    if ( bitstream == NULL )
    {
        snprintf( errortext, ET_SIZE, "AllocBitstream: Memory allocation for Bitstream failed" );
        error( errortext, 100 );
    }
    bitstream->stream_buffer = ( byte * ) calloc( MAX_CODED_FRAME_SIZE, sizeof( byte ) );
    if ( bitstream->stream_buffer == NULL )
    {
        snprintf( errortext, ET_SIZE, "AllocBitstream: Memory allocation for streamBuffer failed" );
        error( errortext, 100 );
    }

    return bitstream;
}

qcoder_env_t* alloc_qcoder()
{
    qcoder_env_t* qc;
    qc = ( qcoder_env_t * )calloc( 1, sizeof( qcoder_env_t ) );
    if( qc == NULL )
    {
        sprintf( errortext, "%s", "alloc_qcoder: Memory allocation for qcoder failed" );
        error( errortext, 100 );
    }

    return qc;
}
/*
*************************************************************************
* Function:Frees a partition structure (array).
* Input:Partition to be freed, size of partition Array (Number of Partitions)
* Output:
* Return:
* Attention:n must be the same as for the corresponding call of AllocPartition
*************************************************************************
*/

void free_bitstream()
{
    assert( currStream != NULL );
    assert( currStream->stream_buffer != NULL );

    free( currStream->stream_buffer );
    free( currStream );
}

/*
*************************************************************************
* Function:Dynamic memory allocation of frame size related global buffers
buffers are defined in global.h, allocated memory must be freed in
void free_global_buffers()
* Input:Input Parameters struct inp_par *inp, Image Parameters struct img_par *img
* Output:Number of allocated bytes
* Return:
* Attention:
*************************************************************************
*/

int init_global_buffers( input_t *inp, image_t *img )
{
    int i, j;
    int refnum;

    int memory_size = 0;
    img->buf_cycle = inp->buf_cycle + 1;

    img->buf_cycle *= 2;

    memory_size += get_mem2D_byte( &imgY_prev, img->height  , img->width );
    memory_size += get_mem3D_byte( &imgUV_prev, 2, img->height   / ( chroma_format == 2 ? 1 : 2 ), img->width_cr );

#if DEBLOCK  //added by ckj
    memory_size += get_mem2D_byte( &p_img_y_dec_deblock, img->height  , img->width );
    memory_size += get_mem3D_byte( &p_img_uv_dec_deblock, 2, img->height   / ( chroma_format == 2 ? 1 : 2 ), img->width_cr );
    memory_size += get_mem2D_byte( &imgY_prev_deblock, img->height  , img->width );
    memory_size += get_mem3D_byte( &imgUV_prev_deblock, 2, img->height   / ( chroma_format == 2 ? 1 : 2 ), img->width_cr );
#endif

    memory_size += get_mem2D_byte( &imgY_ref, img->height  , img->width );
    memory_size += get_mem3D_byte( &imgUV_ref, 2, img->height / ( chroma_format == 2 ? 1 : 2 ), img->width_cr );

    for ( refnum=0; refnum<MAX_REF_NUM_PLUS_1; refnum++ )
    {
        memory_size += get_mem2D_mv( &frm_mv[refnum], ( img->height/8 ) , ( img->width/8 ) );
        memory_size += get_mem4D_mv( &frm_mv_4x4[refnum], ( img->height )/8 , ( img->width )/8, 2 , 2 );
    }
    memory_size += get_mem2D_bi_mv( &frm_bi_mv, ( img->height/8 ) , ( img->width/8 ) );
    memory_size += get_mem4D_bi_mv( &frm_bi_mv_4x4, ( img->height )/8 , ( img->width )/8, 2 , 2 );

    if ( ( ( mb_data ) = ( macroblock_t * ) calloc( ( img->width / MB_BLOCK_SIZE ) * ( img->height  / MB_BLOCK_SIZE ), sizeof( macroblock_t ) ) ) == NULL )
        no_mem_exit( "init_global_buffers: mb_data" );

    img->buf_cycle = inp->buf_cycle + 1;

    // allocate frame buffer
    for ( refnum = 0; refnum < 3; refnum++ )
        for ( i = 0; i < 3; i++ )
        {
            if ( i == 0 )
            {
                get_mem2D_byte( &img_y_dec[refnum],img->height,img->width );
            }
            else
            {
                get_mem2D_byte( &img_uv_dec[i-1][refnum],img->height_cr,img->width_cr );
            }
        }
    p_img_y_dec=img_y_dec[2];
    p_img_uv_dec[0]=img_uv_dec[0][2];
    p_img_uv_dec[1]=img_uv_dec[1][2];

    //forward reference frame buffer
    //ref_frm[0] = reference_frame[0];      //reference_frame[ref_index][yuv][height][width],ref_frm[ref_index][yuv][height][width]
    //ref_frm[1] = reference_frame[1];
    //current_frame = reference_frame[2];

    //luma for backward
    //forward/backward reference buffer
    //f_ref_frm[0] = ref_frm[1];    //f_ref_frm[ref_index][yuv][height(height/2)][width] ref_index=0 for B frame, ref_index = 0,1 for B field
    //b_ref_frm[0] = ref_frm[0];    //b_ref_frm[ref_index][yuv][height(height/2)][width] ref_index=0 for B frame, ref_index = 0,1 for B field
    for ( j = 0; j < 1; j++ )     //ref_index = 0 luma = 0
    {
        //mref_fref_frm[j] = f_ref_frm[j][0];
        //mref_bref_frm[j] = b_ref_frm[j][0];
    }

    //chroma for backward
    for ( j = 0; j < 1; j++ )     //ref_index = 0
        for ( i = 0; i < 2; i++ )   // chroma uv =0,1; 1,2 for reference_frame
        {
            //mcef_fref_frm[j][i] = f_ref_frm[j][i + 1];
            //mcef_bref_frm[j][i] = b_ref_frm[j][i + 1];
        }

    return ( memory_size );
}

/*
*************************************************************************
* Function:Free allocated memory of frame size related global buffers
buffers are defined in global.h, allocated memory is allocated in
int init_global_buffers()
* Input:Input Parameters struct inp_par *inp, Image Parameters struct img_par *img
* Output:
* Return:
* Attention:
*************************************************************************
*/

void free_global_buffers( input_t *inp, image_t *img )
{
    int i, j,refnum;

    free_mem2D_byte( imgY_prev );
    free_mem3D_byte( imgUV_prev, 2 );

#if DEBLOCK //added by ckj
    free_mem2D_byte( p_img_y_dec_deblock );
    free_mem3D_byte( p_img_uv_dec_deblock, 2 );
    free_mem2D_byte( imgY_prev_deblock );
    free_mem3D_byte( imgUV_prev_deblock, 2 );
#endif

    free_mem2D_byte( imgY_ref );
    free_mem3D_byte( imgUV_ref, 2 );

    // free mem, allocated for structure img
    if ( mb_data != NULL )
        free( mb_data );

    for ( i = 0; i < 3; i++ )
    {
        free_mem2D_byte( img_y_dec[i] );
        for ( j = 0; j < 2; j++ )
        {
            //free_mem2D_byte(reference_frame[i][j]);
            free_mem2D_byte( img_uv_dec[j][i] );
        }
    }

    for ( refnum=0; refnum<MAX_REF_NUM_PLUS_1; refnum++ )
    {
        free_mem2D_mv( frm_mv[refnum] );
        free_mem4D_mv( frm_mv_4x4[refnum],( img->height )/8,( img->width )/8 );
    }
    //if (input->succe_b != 0)
    {
        free_mem2D_bi_mv( frm_bi_mv );
        free_mem4D_bi_mv( frm_bi_mv_4x4,( img->height )/8,( img->width )/8 );
    }
}

int get_direct_mv( int ******mv, int mb_x, int mb_y )
{
    int i, j, k, l;

    if ( ( *mv = ( int ***** )calloc( mb_y, sizeof( int **** ) ) ) == NULL )
        no_mem_exit( "get_mem_mv: mv" );
    for ( i = 0; i < mb_y; i++ )
    {
        if ( ( ( *mv )[i] = ( int **** )calloc( mb_x, sizeof( int *** ) ) ) == NULL )
            no_mem_exit( "get_mem_mv: mv" );
        for ( j = 0; j < mb_x; j++ )
        {
            if ( ( ( *mv )[i][j] = ( int *** )calloc( 2, sizeof( int ** ) ) ) == NULL )
                no_mem_exit( "get_mem_mv: mv" );

            for ( k = 0; k < 2; k++ )
            {
                if ( ( ( *mv )[i][j][k] = ( int ** )calloc( 2, sizeof( int * ) ) ) == NULL )
                    no_mem_exit( "get_mem_mv: mv" );
                for ( l = 0; l < 2; l++ )
                    if ( ( ( *mv )[i][j][k][l] = ( int * )calloc( 3, sizeof( int ) ) ) == NULL )
                        no_mem_exit( "get_mem_mv: mv" );
            }
        }
    }
    return mb_x * mb_y * 2 * 2 * 3 * sizeof( int );
}

/*
*************************************************************************
* Function:Free memory from mv
* Input:int****** mv
* Output:
* Return:
* Attention:
*************************************************************************
*/

void free_direct_mv( int *****mv, int mb_x, int mb_y )
{
    int i, j, k, l;

    for ( i = 0; i < mb_y; i++ )
    {
        for ( j = 0; j < mb_x; j++ )
        {
            for ( k = 0; k < 2; k++ )
            {
                for ( l = 0; l < 2; l++ )
                    free( mv[i][j][k][l] );

                free( mv[i][j][k] );
            }
            free( mv[i][j] );
        }
        free( mv[i] );
    }
    free( mv );
}

/*
*************************************************************************
* Function:update the decoder picture buffer
* Input:frame number in the bitstream and the video sequence
* Output:
* Return:
* Attention:
*************************************************************************
*/

void update_picture_buffers()
{
    byte ** tmp_img_y_dec;
    byte ** tmp_img_uv_dec[UV];
    mv_t ** tmp_frm_mv;

    tmp_img_y_dec=img_y_dec[2];
    tmp_img_uv_dec[0]=img_uv_dec[0][2];
    tmp_img_uv_dec[1]=img_uv_dec[1][2];

    img_y_dec[2]=img_y_dec[1];
    img_uv_dec[0][2]=img_uv_dec[0][1];
    img_uv_dec[1][2]=img_uv_dec[1][1];

    img_y_dec[1]=img_y_dec[0];
    img_uv_dec[0][1]=img_uv_dec[0][0];
    img_uv_dec[1][1]=img_uv_dec[1][0];

    img_y_dec[0]=tmp_img_y_dec;
    img_uv_dec[0][0]=tmp_img_uv_dec[0];
    img_uv_dec[1][0]=tmp_img_uv_dec[1];

    p_img_y_dec=img_y_dec[2];
    p_img_uv_dec[0]=img_uv_dec[0][2];
    p_img_uv_dec[1]=img_uv_dec[1][2];

    tmp_frm_mv=frm_mv[1];
    frm_mv[1]=frm_mv[0];
    frm_mv[0]=frm_mv[2];
    frm_mv[2]=tmp_frm_mv;

}
#ifdef OPT_HP
void update_picture_buffers2()
{
	byte ** tmp_img_y_dec;
	byte ** tmp_img_uv_dec[UV];
	mv_t ** tmp_frm_mv;

	tmp_img_y_dec=img_y_dec[1];
	tmp_img_uv_dec[0]=img_uv_dec[0][1];
	tmp_img_uv_dec[1]=img_uv_dec[1][1];

	img_y_dec[1]=img_y_dec[0];
	img_uv_dec[0][1]=img_uv_dec[0][0];
	img_uv_dec[1][1]=img_uv_dec[1][0];

	img_y_dec[0]=tmp_img_y_dec;
	img_uv_dec[0][0]=tmp_img_uv_dec[0];
	img_uv_dec[1][0]=tmp_img_uv_dec[1];

	p_img_y_dec=img_y_dec[2];
	p_img_uv_dec[0]=img_uv_dec[0][2];
	p_img_uv_dec[1]=img_uv_dec[1][2];

	tmp_frm_mv=frm_mv[1];
	frm_mv[1]=frm_mv[0];
	frm_mv[0]=tmp_frm_mv;

}
#endif